package com.whz.gateway.filter;

import com.whz.gateway.common.constants.GatewayConstant;
import com.whz.gateway.common.util.PathMatcherUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import static cn.hutool.core.util.BooleanUtil.isTrue;

/**
 * 全局过滤器
 *
 * @author whz
 */
@Slf4j
public abstract class AbstractGlobalFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (log.isDebugEnabled()) {
            log.debug(" Current Filter: [{}]  =====  path: {}", this.getClass().getSimpleName(), request.getPath());
        }

        // 命中白名单规则
        Boolean match = exchange.getAttribute(GatewayConstant.USER_WHITE_LIST_ATTRIBUTE);
        if (isTrue(match)) {
            log.info("match white list rules =====  path :{}", exchange.getRequest().getPath());
            return chain.filter(exchange);
        }
        // filter 逻辑
        if (shouldFilter(exchange)) {
            return apply(exchange, chain);
        }
        return chain.filter(exchange);
    }

    /**
     * 是否需要过滤
     *
     * @param exchange exchange
     * @return true
     */
    protected abstract boolean shouldFilter(ServerWebExchange exchange);

    /**
     * 具体逻辑
     *
     * @param exchange exchange
     * @param chain    filter chain
     * @return void
     */
    protected abstract Mono<Void> apply(ServerWebExchange exchange, GatewayFilterChain chain);

    /**
     * 匹配路径
     *
     * @param pattern 匹配url
     * @param uriPath 访问路径
     * @return true: 匹配
     */
    protected boolean matchPath(String pattern, RequestPath uriPath) {
        return matchPathString(pattern, uriPath.toString());
    }

    protected boolean matchPathString(String pattern, String uriPath) {
        return PathMatcherUtils.match(pattern, uriPath);
    }
}